/**
 * jz-h5-scanCode 扫码插件主入口
 * 提供与uni.scanCode一致的API接口
 * H5环境使用自定义扫码实现，其他平台使用uni原生扫码
 */

import CameraScanner from './cameraScanner.js'
import QRCodeDecoder from './qrCodeDecoder.js'
import UIManager from './uiManager.js'

class JzH5ScanCode {
    constructor() {
        this.cameraScanner = new CameraScanner();
        this.qrCodeDecoder = new QRCodeDecoder();
        this.uiManager = new UIManager();
        this.isScanning = false;
        this.isInitializing = false;
        this.currentOptions = null;
        this.scanAnimationId = null;
        this.scanLoopActive = false;
        this.lastScanTime = 0;
        this.scanInterval = 300; // 增加扫码间隔到300ms，减少CPU占用
        this.isDecoding = false; // 添加解码状态标记，避免重复解码
        
        // 绑定事件处理器，确保this指向正确且可以正确移除
        this.boundHandleUIClose = this.handleUIClose.bind(this);
        this.boundHandleFileSelected = this.handleFileSelected.bind(this);
        
        // 预初始化解码器（后台进行）
        this.preInitializeDecoder();
    }

    /**
     * 预初始化解码器（后台异步进行）
     */
    async preInitializeDecoder() {
        try {
            // 使用 setTimeout 确保不阻塞主线程
            setTimeout(async () => {
                await this.qrCodeDecoder.init();
                console.log('解码器预初始化完成');
            }, 100);
        } catch (error) {
            console.warn('解码器预初始化失败:', error);
        }
    }

    /**
     * 检查当前是否为H5环境
     */
    isH5Environment() {
        // 检查是否在uni-app的H5环境中
        if (typeof uni !== 'undefined' && uni.getSystemInfoSync) {
            try {
                const systemInfo = uni.getSystemInfoSync();
                return systemInfo.platform === 'devtools' || systemInfo.uniPlatform === 'web';
            } catch (error) {
                console.warn('获取系统信息失败:', error);
            }
        }
        
        // 检查是否在浏览器环境中
        return typeof window !== 'undefined' && typeof document !== 'undefined' && !window.plus && !window.wx && !window.my;
    }

    /**
     * 扫码方法 - 与uni.scanCode API保持一致
     * @param {Object} options - 扫码参数
     */
    scanCode(options = {}) {
        // 防止重复调用
        if (this.isScanning || this.isInitializing) {
            console.warn('扫码正在进行中，忽略重复调用');
            if (options.fail) {
                options.fail({ errMsg: 'scanCode:fail busy' });
            }
            if (options.complete) {
                options.complete({ errMsg: 'scanCode:fail busy' });
            }
            return;
        }

        // 如果不是H5环境，直接使用uni.scanCode
        if (!this.isH5Environment()) {
            return this.useUniScanCode(options);
        }

        // H5环境使用自定义扫码实现
        return this.useH5ScanCode(options);
    }

    /**
     * 使用uni原生扫码接口
     */
    useUniScanCode(options) {
        if (typeof uni === 'undefined' || !uni.scanCode) {
            const error = '当前环境不支持uni.scanCode';
            if (options.fail) {
                options.fail({ errMsg: error });
            }
            if (options.complete) {
                options.complete({ errMsg: error });
            }
            return;
        }

        console.log('使用uni原生扫码接口');
        uni.scanCode(options);
    }

    /**
     * 使用H5自定义扫码实现
     */
    async useH5ScanCode(options) {
        if (this.isInitializing) {
            console.warn('扫码初始化中，请稍后重试');
            if (options.fail) {
                options.fail({ errMsg: 'scanCode:fail initializing' });
            }
            if (options.complete) {
                options.complete({ errMsg: 'scanCode:fail initializing' });
            }
            return;
        }

        this.isInitializing = true;
        
        try {
            console.log('使用H5自定义扫码实现');
            this.currentOptions = options;

            // 使用 Promise 和 setTimeout 避免阻塞
            await new Promise(resolve => setTimeout(resolve, 0));

            // 快速检查摄像头支持情况（不等待权限）
            const hasMediaDevices = !!(navigator.mediaDevices && navigator.mediaDevices.getUserMedia);
            
            // 如果明确要求仅相册或没有摄像头API，直接进入图片选择模式
            if (options.onlyFromCamera === false || !hasMediaDevices) {
                await this.startImagePickerMode();
                return;
            }

            // 并行执行UI创建和摄像头检查
            const [uiResult, cameraResult] = await Promise.allSettled([
                this.createScannerUI(options),
                this.checkAndInitCamera(options)
            ]);

            // 检查UI创建结果
            if (uiResult.status === 'rejected') {
                throw new Error('UI创建失败: ' + uiResult.reason.message);
            }

            // 检查摄像头初始化结果
            if (cameraResult.status === 'rejected') {
                console.log('摄像头初始化失败，降级到图片选择模式:', cameraResult.reason.message);
                // 清理已创建的UI
                this.uiManager.removeScannerUI();
                await this.startImagePickerMode();
                return;
            }

            const canvasElement = uiResult.value;
            
            // 绑定事件（必须在UI创建后）
            this.bindUIEvents();
            
            // 启动扫码循环
            this.isScanning = true;
            this.startScanLoop();

            console.log('H5扫码已启动');
            
        } catch (error) {
            console.error('启动扫码失败:', error);
            
            // 清理状态
            this.cleanup();
            
            // 尝试降级到图片选择模式
            if (this.isCameraError(error)) {
                console.log('摄像头相关错误，尝试降级到图片选择模式');
                try {
                    await this.startImagePickerMode();
                    return;
                } catch (fallbackError) {
                    console.error('图片选择模式也失败:', fallbackError);
                }
            }
            
            const errorMsg = 'scanCode:fail ' + error.message;
            if (options.fail) {
                options.fail({ errMsg: errorMsg });
            }
            if (options.complete) {
                options.complete({ errMsg: errorMsg });
            }
        } finally {
            this.isInitializing = false;
        }
    }

    /**
     * 创建扫码UI（异步，非阻塞）
     */
    async createScannerUI(options) {
        return new Promise((resolve, reject) => {
            try {
                // 使用 setTimeout 确保不阻塞主线程
                setTimeout(() => {
                    try {
                        const uiOptions = {
                            scanFrameColor: options.scanFrameColor || '#00ff00'
                        };
                        const canvasElement = this.uiManager.createScannerUI(uiOptions);
                        
                        // 根据参数配置UI
                        this.configureUI(options);
                        
                        resolve(canvasElement);
                    } catch (error) {
                        reject(error);
                    }
                }, 10);
            } catch (error) {
                reject(error);
            }
        });
    }

    /**
     * 检查并初始化摄像头（异步，带超时）
     */
    async checkAndInitCamera(options, timeout = 5000) {
        return new Promise(async (resolve, reject) => {
            const timeoutId = setTimeout(() => {
                reject(new Error('摄像头初始化超时'));
            }, timeout);

            try {
                // 检查摄像头可用性（快速检查）
                const cameraSupported = await this.checkCameraAvailability();
                if (!cameraSupported) {
                    clearTimeout(timeoutId);
                    reject(new Error('摄像头不可用'));
                    return;
                }

                // 等待解码器就绪（带超时）
                await this.waitForDecoderReady(2000);

                // 初始化摄像头
                const cameraConfig = this.buildCameraConfig(options);
                
                // 创建临时canvas用于初始化
                const tempCanvas = document.createElement('canvas');
                await this.cameraScanner.init(tempCanvas, cameraConfig);

                clearTimeout(timeoutId);
                resolve();
            } catch (error) {
                clearTimeout(timeoutId);
                reject(error);
            }
        });
    }

    /**
     * 检查摄像头可用性（优化版，减少等待时间）
     */
    async checkCameraAvailability() {
        try {
            // 快速检查基础API支持
            if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
                return false;
            }

            // 使用Promise.race添加超时机制
            const checkPromise = this.performCameraCheck();
            const timeoutPromise = new Promise((_, reject) => 
                setTimeout(() => reject(new Error('检查超时')), 3000)
            );

            const result = await Promise.race([checkPromise, timeoutPromise]);
            return result;
        } catch (error) {
            console.log('摄像头检查失败:', error.message);
            return false;
        }
    }

    /**
     * 执行摄像头检查
     */
    async performCameraCheck() {
        try {
            // 检查设备列表
            const devices = await navigator.mediaDevices.enumerateDevices();
            const hasCamera = devices.some(device => device.kind === 'videoinput');
            
            if (!hasCamera) {
                return false;
            }

            // 尝试获取摄像头权限（快速测试）
            const stream = await navigator.mediaDevices.getUserMedia({ 
                video: { 
                    facingMode: 'environment',
                    width: { ideal: 640 },
                    height: { ideal: 480 }
                } 
            });
            
            // 立即关闭流
            stream.getTracks().forEach(track => track.stop());
            return true;
        } catch (error) {
            console.log('摄像头权限或可用性检查失败:', error.message);
            return false;
        }
    }

    /**
     * 启动图片选择模式（优化版）
     */
    async startImagePickerMode() {
        try {
            console.log('启动图片选择模式');
            
            // 确保解码器就绪
            await this.waitForDecoderReady(3000);
            
            // 使用 Promise 包装文件选择，避免阻塞
            return new Promise((resolve, reject) => {
                // 使用 setTimeout 确保不阻塞主线程
                setTimeout(() => {
                    try {
                        const fileInput = document.createElement('input');
                        fileInput.type = 'file';
                        fileInput.accept = 'image/*';
                        fileInput.capture = 'environment';
                        fileInput.style.display = 'none';
                        
                        document.body.appendChild(fileInput);
                        
                        const cleanup = () => {
                            if (document.body.contains(fileInput)) {
                                document.body.removeChild(fileInput);
                            }
                        };
                        
                        fileInput.addEventListener('change', async (event) => {
                            const file = event.target.files[0];
                            cleanup();
                            
                            if (file) {
                                try {
                                    await this.processSelectedImage(file);
                                    resolve();
                                } catch (error) {
                                    reject(error);
                                }
                            } else {
                                this.handleScanCancel();
                                resolve();
                            }
                        });
                        
                        // 添加取消处理
                        const handleCancel = () => {
                            cleanup();
                            this.handleScanCancel();
                            resolve();
                        };
                        
                        // 监听窗口焦点，检测用户是否取消了文件选择
                        let focusHandler;
                        const setupCancelDetection = () => {
                            focusHandler = () => {
                                setTimeout(() => {
                                    if (!fileInput.files.length) {
                                        window.removeEventListener('focus', focusHandler);
                                        handleCancel();
                                    }
                                }, 300);
                            };
                            window.addEventListener('focus', focusHandler);
                        };
                        
                        setupCancelDetection();
                        fileInput.click();
                        
                    } catch (error) {
                        reject(error);
                    }
                }, 10);
            });
            
        } catch (error) {
            console.error('启动图片选择模式失败:', error);
            throw error;
        }
    }

    /**
     * 处理选择的图片（优化版）
     */
    async processSelectedImage(file) {
        return new Promise((resolve, reject) => {
            try {
                console.log('开始处理选择的图片:', file.name);
                
                const img = new Image();
                const reader = new FileReader();
                
                // 设置超时
                const timeoutId = setTimeout(() => {
                    reject(new Error('图片处理超时'));
                }, 10000);
                
                const cleanup = () => {
                    clearTimeout(timeoutId);
                };
                
                img.onload = async () => {
                    cleanup();
                    try {
                        // 使用 setTimeout 避免阻塞
                        setTimeout(async () => {
                            try {
                                const scanTypes = this.currentOptions?.scanType || [];
                                const result = await this.qrCodeDecoder.decode(img, scanTypes);
                                
                                if (result) {
                                    console.log('图片解码成功:', result.text);
                                    this.handleScanSuccess(result, 'album');
                                    resolve(result);
                                } else {
                                    const error = '图片中未找到指定类型的条码';
                                    this.handleScanError(error);
                                    reject(new Error(error));
                                }
                            } catch (error) {
                                this.handleScanError('图片解码失败: ' + error.message);
                                reject(error);
                            }
                        }, 10);
                    } catch (error) {
                        reject(error);
                    }
                };
                
                img.onerror = () => {
                    cleanup();
                    const error = '图片加载失败';
                    this.handleScanError(error);
                    reject(new Error(error));
                };
                
                reader.onload = (e) => {
                    img.src = e.target.result;
                };
                
                reader.onerror = () => {
                    cleanup();
                    const error = '文件读取失败';
                    this.handleScanError(error);
                    reject(new Error(error));
                };
                
                reader.readAsDataURL(file);
                
            } catch (error) {
                reject(error);
            }
        });
    }

    /**
     * 处理扫码取消
     */
    handleScanCancel() {
        this.cleanup();
        
        if (this.currentOptions) {
            const errorMsg = 'scanCode:fail cancel';
            if (this.currentOptions.fail) {
                this.currentOptions.fail({ errMsg: errorMsg });
            }
            if (this.currentOptions.complete) {
                this.currentOptions.complete({ errMsg: errorMsg });
            }
        }
    }

    /**
     * 清理资源和状态
     */
    cleanup() {
        this.isScanning = false;
        this.isInitializing = false;
        this.scanLoopActive = false;
        this.isDecoding = false; // 重置解码状态
        
        if (this.scanAnimationId) {
            cancelAnimationFrame(this.scanAnimationId);
            this.scanAnimationId = null;
        }
    }

    /**
     * 判断是否为摄像头相关错误
     */
    isCameraError(error) {
        const errorMessage = error.message || error.toString();
        const cameraErrorKeywords = [
            'camera', 'getUserMedia', 'permission', 'NotAllowedError',
            'NotFoundError', 'NotReadableError', 'OverconstrainedError',
            'AbortError', '摄像头', '权限', '超时'
        ];
        
        return cameraErrorKeywords.some(keyword => 
            errorMessage.toLowerCase().includes(keyword.toLowerCase())
        );
    }

    /**
     * 根据参数配置UI
     */
    configureUI(options) {
        // 使用 setTimeout 避免阻塞
        setTimeout(() => {
            const { onlyFromCamera } = options;
            
            if (onlyFromCamera) {
                const albumBtn = document.querySelector('.jz-scanner-select');
                if (albumBtn) {
                    albumBtn.style.display = 'none';
                }
            }
        }, 10);
    }

    /**
     * 构建摄像头配置
     */
    buildCameraConfig(options) {
        return {
            width: 1280,
            height: 720,
            facingMode: 'environment'
        };
    }

    /**
     * 绑定UI事件
     */
    bindUIEvents() {
        document.addEventListener('jz-scanner-close', this.boundHandleUIClose);
        document.addEventListener('jz-scanner-file-selected', this.boundHandleFileSelected);
        console.log('UI事件已绑定');
    }

    /**
     * 解绑UI事件
     */
    unbindUIEvents() {
        document.removeEventListener('jz-scanner-close', this.boundHandleUIClose);
        document.removeEventListener('jz-scanner-file-selected', this.boundHandleFileSelected);
        console.log('UI事件已解绑');
    }

    /**
     * 等待解码器初始化完成（优化版）
     */
    async waitForDecoderReady(timeout = 3000) {
        const startTime = Date.now();
        
        while (!(await this.qrCodeDecoder.isReady())) {
            if (Date.now() - startTime > timeout) {
                throw new Error('解码器初始化超时');
            }
            // 使用更短的等待间隔，但通过 requestAnimationFrame 优化
            await new Promise(resolve => requestAnimationFrame(() => setTimeout(resolve, 50)));
        }
        
        console.log('解码器已就绪:', this.qrCodeDecoder.getDecoderType());
    }

    /**
     * 停止扫码
     */
    async stopScan() {
        try {
            this.cleanup();
            
            await this.cameraScanner.stop();
            this.uiManager.removeScannerUI();
            this.unbindUIEvents();
            
            console.log('扫码已停止');
        } catch (error) {
            console.error('停止扫码失败:', error);
        }
    }

    /**
     * 处理UI关闭事件
     */
    handleUIClose() {
        console.log('处理UI关闭事件');
        
        if (this.isScanning || this.isInitializing) {
            this.stopScan();
            
            if (this.currentOptions) {
                const errorMsg = 'scanCode:fail cancel';
                
                if (this.currentOptions.fail) {
                    this.currentOptions.fail({ errMsg: errorMsg });
                }
                if (this.currentOptions.complete) {
                    this.currentOptions.complete({ errMsg: errorMsg });
                }
            }
        } else {
            this.uiManager.removeScannerUI();
            this.unbindUIEvents();
        }
    }

    /**
     * 处理选择图片事件
     */
    async handleFileSelected(event) {
        const file = event.detail.file;
        if (!file || !this.qrCodeDecoder) {
            return;
        }

        try {
            console.log('开始扫描图片文件:', file.name);
            
            // 异步处理，避免阻塞
            setTimeout(async () => {
                const img = new Image();
                img.onload = async () => {
                    try {
                        const scanTypes = this.currentOptions?.scanType || [];
                        const result = await this.qrCodeDecoder.decode(img, scanTypes);
                        
                        if (result) {
                            console.log('UI图片扫码成功:', result.text);
                            this.handleScanSuccess(result, 'album');
                        } else {
                            this.uiManager.showErrorMessage('图片中未找到指定类型的条码');
                        }
                    } catch (error) {
                        console.error('图片扫码失败:', error);
                        this.uiManager.showErrorMessage('图片扫码失败');
                    }
                };
                
                img.onerror = () => {
                    this.uiManager.showErrorMessage('图片加载失败');
                };
                
                const reader = new FileReader();
                reader.onload = (e) => {
                    img.src = e.target.result;
                };
                reader.readAsDataURL(file);
            }, 10);
            
        } catch (error) {
            console.error('处理图片文件失败:', error);
            this.uiManager.showErrorMessage('处理图片文件失败');
        }
    }

    /**
     * 扫码循环（优化版，防止卡顿）
     */
    startScanLoop() {
        if (!this.isScanning || this.scanLoopActive) {
            return;
        }

        this.scanLoopActive = true;
        
        const scanFrame = async () => {
            if (!this.isScanning || !this.scanLoopActive) {
                this.scanLoopActive = false;
                return;
            }

            const now = Date.now();
            
            // 控制扫码频率，避免过于频繁
            if (now - this.lastScanTime < this.scanInterval) {
                this.scanAnimationId = requestAnimationFrame(scanFrame);
                return;
            }

            // 如果正在解码，跳过本次扫码
            if (this.isDecoding) {
                this.scanAnimationId = requestAnimationFrame(scanFrame);
                return;
            }

            this.lastScanTime = now;

            try {
                const imageData = this.cameraScanner.getImageData();
                if (imageData) {
                    const scanTypes = this.currentOptions?.scanType || [];
                    
                    // 标记开始解码
                    this.isDecoding = true;
                    
                    // 使用 setTimeout 确保解码不阻塞渲染，并增加延迟
                    setTimeout(async () => {
                        try {
                            const result = await this.qrCodeDecoder.decode(imageData, scanTypes);
                            if (result && this.isScanning) {
                                console.log('摄像头扫码成功:', result);
                                this.handleScanSuccess(result, 'camera');
                                return;
                            }
                        } catch (error) {
                            // 忽略解码错误，继续扫码
                        } finally {
                            // 解码完成，重置标记
                            this.isDecoding = false;
                        }
                    }, 50); // 增加延迟到50ms
                }
            } catch (error) {
                console.warn('扫码过程中出错:', error);
                this.isDecoding = false;
            }

            // 继续下一帧
            this.scanAnimationId = requestAnimationFrame(scanFrame);
        };

        this.scanAnimationId = requestAnimationFrame(scanFrame);
    }

    /**
     * 处理扫码成功
     */
    handleScanSuccess(result, imageChannel = 'camera') {
        console.log('扫码成功:', result.text);
        
        // 立即停止扫码循环
        this.cleanup();
        
        // 震动反馈
        if (navigator.vibrate) {
            navigator.vibrate(200);
        }

        // 构建返回数据
        const scanResult = this.buildScanResult(result, imageChannel);

        // 异步执行清理和回调，避免阻塞
        setTimeout(() => {
            this.stopScan();
            
            if (this.currentOptions) {
                if (this.currentOptions.success) {
                    this.currentOptions.success(scanResult);
                }
                if (this.currentOptions.complete) {
                    this.currentOptions.complete(scanResult);
                }
            }
        }, 0);
    }

    /**
     * 构建扫码结果，与uni.scanCode返回格式一致
     */
    buildScanResult(result, imageChannel) {
        const scanResult = {
            result: result.text,
            scanType: result.scanType || this.detectScanType(result.text),
            charSet: 'UTF-8',
            errMsg: 'scanCode:ok'
        };

        if (imageChannel) {
            scanResult.imageChannel = imageChannel;
        }

        if (result.format) {
            scanResult.format = result.format;
        }

        if (result.data) {
            try {
                scanResult.rawData = btoa(result.text);
            } catch (error) {
                scanResult.rawData = result.text;
            }
        }

        return scanResult;
    }

    /**
     * 检测扫码类型
     */
    detectScanType(content) {
        return 'qrCode';
    }

    /**
     * 处理扫码错误
     */
    handleScanError(error) {
        console.error('扫码错误:', error);
        this.cleanup();
        
        // 异步执行清理和回调
        setTimeout(() => {
            this.stopScan();

            if (this.currentOptions) {
                const errorMsg = 'scanCode:fail ' + error;
                
                if (this.currentOptions.fail) {
                    this.currentOptions.fail({ errMsg: errorMsg });
                }
                if (this.currentOptions.complete) {
                    this.currentOptions.complete({ errMsg: errorMsg });
                }
            }
        }, 0);
    }

    /**
     * 检查是否支持摄像头
     */
    static async isCameraSupported() {
        try {
            if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
                return false;
            }

            const devices = await navigator.mediaDevices.enumerateDevices();
            return devices.some(device => device.kind === 'videoinput');
        } catch (error) {
            return false;
        }
    }

    /**
     * 获取可用摄像头列表
     */
    static async getCameras() {
        return await CameraScanner.getCameras();
    }

    /**
     * 检查是否支持原生条码检测
     */
    static isBarcodeDetectorSupported() {
        return QRCodeDecoder.isBarcodeDetectorSupported();
    }

    /**
     * 获取支持的条码格式
     */
    static async getSupportedFormats() {
        return await QRCodeDecoder.getSupportedFormats();
    }

    /**
     * 获取插件信息
     */
    static getPluginInfo() {
        return {
            name: 'jz-h5-scanCode',
            version: '1.0.0',
            description: 'H5环境下的二维码扫描插件，与uni.scanCode API兼容',
            author: 'JZ',
            cameraSupported: navigator.mediaDevices && navigator.mediaDevices.getUserMedia,
            barcodeDetectorSupported: 'BarcodeDetector' in window,
            platforms: {
                h5: '自定义扫码实现',
                app: 'uni.scanCode',
                'mp-weixin': 'uni.scanCode',
                'mp-alipay': 'uni.scanCode',
                'mp-baidu': 'uni.scanCode'
            }
        };
    }
}

// 创建单例实例
const jzH5ScanCode = new JzH5ScanCode();

// 导出与uni.scanCode兼容的接口
export default {
    scanCode: (options) => jzH5ScanCode.scanCode(options),
    
    // 静态方法
    isCameraSupported: JzH5ScanCode.isCameraSupported,
    getCameras: JzH5ScanCode.getCameras,
    isBarcodeDetectorSupported: JzH5ScanCode.isBarcodeDetectorSupported,
    getSupportedFormats: JzH5ScanCode.getSupportedFormats,
    getPluginInfo: JzH5ScanCode.getPluginInfo,
    
    // 便捷方法：直接扫描图片
    scanFromImage: (options = {}) => {
        return jzH5ScanCode.scanCode({
            ...options,
            onlyFromCamera: false,
        });
    },
    
    // 便捷方法：检查设备能力并选择最佳扫码模式
    smartScan: async (options = {}) => {
        const cameraSupported = await JzH5ScanCode.isCameraSupported();
        console.log('设备摄像头支持:', cameraSupported);
        
        if (!cameraSupported) {
            console.log('摄像头不可用，使用图片选择模式');
            return jzH5ScanCode.scanCode({
                ...options,
                onlyFromCamera: false,
            });
        } else {
            console.log('摄像头可用，使用标准扫码模式');
            return jzH5ScanCode.scanCode(options);
        }
    },
    
    // 兼容旧版本的方法名
    startScan: (options) => {
        console.warn('startScan方法已废弃，请使用scanCode方法');
        return jzH5ScanCode.scanCode({
            success: options.onSuccess,
            fail: options.onError,
            ...options
        });
    }
};
